﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Store;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.QueryParsers;
using Lucene.Net.Documents;
using System.IO;
using Lucene.Net.Analysis;

namespace LuceneDemo
{
    public class HelloLucene
    {
        private Lucene.Net.Store.Directory index;
        private IndexWriter writer;
        private List<FileInfo> queue = new List<FileInfo>();

        public static void Main(String[] args)// throws IOException {
        {
            Console.WriteLine("Enter the path where the index will be created: ");

            //BufferedReader br = new BufferedReader(
            //        new InputStreamReader(System.in));
            String s = Console.ReadLine();

            HelloLucene indexer = null;
            try
            {
                indexer = new HelloLucene(s);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Cannot create index..." + ex.Message);
            }

            //===================================================
            //read input from user until he enters q for quit
            //===================================================
            while (!s.Equals("q"))
            {
                try
                {
                    Console.WriteLine("Enter the file or folder name to add into the index (q=quit):");
                    Console.WriteLine("[Acceptable file types: .xml, .html, .html, .txt, .js, .css]");
                    s = Console.ReadLine();
                    if (!s.Equals("q"))
                    {
                        //break;
                        //try to add file into the index
                        indexer.IndexFileOrDirectory(s);
                    }

                    ////try to add file into the index
                    //indexer.IndexFileOrDirectory(s);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error indexing " + s + " : " + e.Message);
                }
            }
            indexer.closeIndex();

            indexer = null;
            try
            {
                indexer = new HelloLucene(s);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Cannot create index..." + ex.Message);
            }

            while (!s.Equals("Q"))
            {
                try
                {
                    Console.WriteLine("Enter your search (q=quit):");
                    Console.WriteLine("[Acceptable file types: .xml, .html, .html, .txt]");
                    s = Console.ReadLine();
                    if (s.Equals("Q"))
                    {
                        break;
                    }

                    //search the index
                    indexer.SearchIndex(s);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error indexing " + s + " : " + e.Message);
                }
            }


            //===================================================
            //after adding, we always have to call the
            //closeIndex, otherwise the index is not created    
            //===================================================
            indexer.closeIndex();
        }

        /// <summary>
        /// Constructor 
        /// </summary>
        /// <param name="indexDir">Directory path to where the index should be stored</param>
        HelloLucene(String indexDir)
        {
            // the boolean true parameter means to create a new index everytime, 
            // potentially overwriting any existing files there.
            //
            //writer = new IndexWriter(indexDir, new StandardAnalyzer(), true, IndexWriter.MaxFieldLength.LIMITED);
            index = FSDirectory.GetDirectory(indexDir, false);
            writer = new IndexWriter(index, new SimpleAnalyzer(), true);
        }
        
        /// <summary>
        /// Index file or directory
        /// </summary>
        /// <param name="fileName">Name of file or folder</param>
        public void IndexFileOrDirectory(String fileName)
        {
            ListFiles(fileName);

            int originalNumDocs = writer.DocCount();
            foreach (FileInfo f in queue)
            {
                StreamReader fr = null;
                try
                {
                    Document doc = new Document();

                    //===================================================
                    // add contents of file
                    //===================================================
                    fr = f.OpenText();
                    doc.Add(new Field("contents", fr));

                    //===================================================
                    //adding second field which contains the path of the file
                    //===================================================
                    //doc.Add(new Field("path", fileName,
                    //        Field.Store.YES,
                    //        Field.Index.NOT_ANALYZED)); 
                    doc.Add(new Field("path", fileName,
                          Field.Store.YES,
                          Field.Index.UN_TOKENIZED));

                    writer.AddDocument(doc);
                    Console.WriteLine("Added: " + f.FullName);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Could not add: " + f.FullName);
                }
                finally
                {
                    fr.Close();
                }
            }

            int newNumDocs = writer.DocCount();
            Console.WriteLine("");
            Console.WriteLine("************************");
            Console.WriteLine((newNumDocs - originalNumDocs) + " documents added.");
            Console.WriteLine("************************");

            queue.Clear();
        }

        private void ListFiles(string file)
        {
            if (!File.Exists(file))
            {
                DirectoryInfo di = new DirectoryInfo(file);
                if (di.Exists)
                {
                    foreach (FileInfo fi in di.GetFiles())
                    {
                        ListFiles(fi.FullName);
                    }
                    foreach (DirectoryInfo d in di.GetDirectories())
                    {
                        ListFiles(d.FullName);
                    }
                }
            }
            else
            {
                FileInfo fi = new FileInfo(file);
                string filename = fi.FullName.ToLower();
                //===================================================
                // Only index text files
                //===================================================
                if (filename.EndsWith(".htm") || filename.EndsWith(".html") ||
                        filename.EndsWith(".xml") || filename.EndsWith(".txt") ||
                        filename.EndsWith(".js") || filename.EndsWith(".css"))
                {
                    queue.Add(fi);
                }
                else
                {
                    Console.WriteLine("Skipped " + filename);
                }
            }
        }

        /// <summary>
        /// Search the Index
        /// </summary>
        /// <param name="queryString">String to search for</param>
        public void SearchIndex(string queryString)
        {
            //Query q = new QueryParser("contents", new StandardAnalyzer()).Parse(queryString);
            Query q = new QueryParser("contents", new SimpleAnalyzer()).Parse(queryString);
            IndexSearcher searcher = new IndexSearcher(index);
            int hitsPerPage = 10;
            TopDocCollector collector = new TopDocCollector(hitsPerPage);
            searcher.Search(q, collector);
            ScoreDoc[] hits = collector.TopDocs().scoreDocs;

            Console.WriteLine("Found " + hits.Length + " hits.");
                for (int i = 0; i < hits.Length; ++i)
                {
                    int docId = hits[i].doc;
                    Document d = searcher.Doc(docId);
                    Console.WriteLine((i + 1) + ". " + d.Get("title"));
                }

        }

        /// <summary>
        /// Close index
        /// </summary>
        public void closeIndex() 
        {
            writer.Optimize();
            writer.Close();
        }

        //public static void Main(String[] args)// throws IOException, ParseException {
        //{
        //    // 0. Specify the analyzer for tokenizing text.
        //    //    The same analyzer should be used for indexing and searching
        //    StandardAnalyzer analyzer = new StandardAnalyzer();

        //    // 1. create the index
        //    Directory index = new RAMDirectory();

        //    // the boolean arg in the IndexWriter ctor means to
        //    // create a new index, overwriting any existing index
        //    IndexWriter w = new IndexWriter(index, analyzer, true); //,
        //    //KeepOnlyLastCommitDeletionPolicy);  //MaxFieldLength.UNLIMITED
        //    addDoc(w, "Lucene in Action");
        //    addDoc(w, "Lucene for Dummies");
        //    addDoc(w, "Managing Gigabytes");
        //    addDoc(w, "The Art of Computer Science");
        //    addDoc(w, "Lucene in Action2");
        //    addDoc(w, "Lucene3 for Dummies");
        //    addDoc(w, "Managing4 Gigabytes");
        //    addDoc(w, "The Art of Computer Science - 2");
        //    w.Close();

        //    // 2. query
        //    String querystr = args.Length > 0 ? args[0] : "lucene";

        //    // the "title" arg specifies the default field to use
        //    // when no field is explicitly specified in the query.
        //    Query q = new QueryParser("title", analyzer).Parse(querystr);

        //    // 3. search
        //    int hitsPerPage = 10;
        //    IndexSearcher searcher = new IndexSearcher(index);
        //    TopDocCollector collector = new TopDocCollector(hitsPerPage);
        //    searcher.Search(q, collector);
        //    ScoreDoc[] hits = collector.TopDocs().scoreDocs;

        //    // 4. display results
        //    Console.WriteLine("Found " + hits.Length + " hits.");
        //    for (int i = 0; i < hits.Length; ++i)
        //    {
        //        int docId = hits[i].doc;
        //        Document d = searcher.Doc(docId);
        //        Console.WriteLine((i + 1) + ". " + d.Get("title"));
        //    }

        //    // searcher can only be closed when there
        //    // is no need to access the documents any more. 
        //    searcher.Close();
        //}

        //private static void addDoc(IndexWriter w, String value)// throws IOException {
        //{
        //    Document doc = new Document();
        //    //doc.Add(new Field("title", value, Field.Store.YES, Field.Index.ANALYZED));
        //    doc.Add(new Field("title", value, Field.Store.YES, Field.Index.TOKENIZED));
        //    w.AddDocument(doc);
        //}
    }
}
